<template>
  <div>
    <div style="display: flex; flex-direction: row; margin-bottom: 20px;">
      <el-button v-if="multipleSelection && multipleSelection.length > 0" size="medium" type="danger"
        icon="el-icon-delete" @click="deleteData">
        删除数据
      </el-button>
      <el-button size="medium" type="primary" icon="el-icon-plus" @click="create">
        新增数据
      </el-button>
      <el-button size="medium" icon="el-icon-setting" @click="drawerVisible = true">
        解析方式
      </el-button>
      <el-button :loading="loading" style="margin-left: auto;" size="medium" icon="el-icon-refresh" @click="refresh">
        刷新
      </el-button>
    </div>
    <el-table v-loading="loading" :data="tableData" style="width: 100%" :border="true"
      @selection-change="multipleSelection = $event">
      <el-table-column :align="'center'" type="selection" width="50">
      </el-table-column>
      <el-table-column :align="'center'" label="行键">
        <template v-slot="scope">
          <span class="value" @dblclick="openJsonView('行键', scope.row['rowKey'])">
            {{ scope.row['rowKey'] }}
          </span>
        </template>
      </el-table-column>
      <el-table-column v-for="column in columns" :key="column.family" :align="'center'" :label="column.family">
        <el-table-column v-for="qualifier in column.qualifiers" :key="`${column.family}:${qualifier}`" :align="'center'"
          :label="qualifier">
          <template v-slot="scope">
            <span class="value"
              @dblclick="openJsonView(`${column.family} : ${qualifier}`, scope.row[`${column.family}:${qualifier}`])">
              {{ scope.row[`${column.family}:${qualifier}`] }}
            </span>
          </template>
        </el-table-column>
      </el-table-column>
      <el-table-column :align="'center'" label="操作" width="180">
        <template v-slot="scope">
          <el-button size="small" class="el-icon-edit-outline" @click="show(scope.row)">
            查看
          </el-button>
          <el-button size="small" class="el-icon-delete" @click="deleteRow(scope.row)">
            删除
          </el-button>
        </template>
      </el-table-column>
      <el-empty slot="empty" description="暂无数据"></el-empty>
    </el-table>
    <el-dialog :title="dialogMode === 'view' ? '查看数据' : '新增数据'" :visible.sync="dialogVisible" :append-to-body="true">
      <el-form>
        <el-form-item>
          <div style="display: flex;justify-content: left;align-items:baseline">
            <el-tooltip placement="top">
              <div slot="content">行键</div>
              <el-input :readonly="dialogMode === 'view'" v-model="row.rowKey" placeholder="行键" size="medium"
                style="flex: 1;">
              </el-input>
            </el-tooltip>
            <div :style="{ width: dialogMode === 'view' ? '25px' : '5px' }"></div>
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '行键的数据类型' : '选择行键的数据类型' }}</div>
              <el-select :disabled="dialogMode === 'view'" v-model="row.rowKeyDataType" placeholder="数据类型" size="medium"
                style="width: 150px;">
                <el-option v-for="item in dataTypes" :key="item" :label="item" :value="item">
                </el-option>
              </el-select>
            </el-tooltip>
          </div>
        </el-form-item>
        <el-form-item v-for="cell in row.cells" :key="cell.key">
          <div style="display: flex; justify-content: space-between; align-items:baseline;">
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '列族' : '选择列族' }}</div>
              <el-select :disabled="dialogMode === 'view'" v-model="cell.family" placeholder="列族" size="medium"
                style="width: 150px;">
                <el-option v-for="family in families" :key="family.name" :label="family.name" :value="family.name">
                </el-option>
              </el-select>
            </el-tooltip>
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '列限定符' : '填写列限定符' }}</div>
              <el-input :readonly="dialogMode === 'view'" v-model="cell.qualifier" placeholder="列限定符" size="medium"
                style="width: 150px;">
              </el-input>
            </el-tooltip>
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '单元格数据' : '单元格数据' }}</div>
              <el-input :readonly="dialogMode === 'view'" v-model="cell.value" placeholder="数据" size="medium"
                style="width: 150px;">
              </el-input>
            </el-tooltip>
            <el-tooltip placement="top">
              <div slot="content">{{ dialogMode === 'view' ? '数据类型' : '选择数据类型' }}</div>
              <el-select :disabled="dialogMode === 'view'" v-model="cell.valueDataType" placeholder="数据类型" size="medium"
                style="width: 150px;">
                <el-option v-for="item in dataTypes" :key="item" :label="item" :value="item">
                </el-option>
              </el-select>
            </el-tooltip>
            <el-button v-if="dialogMode !== 'view'" @click="removeCell(cell.key)" type="danger" size="medium"
              icon="el-icon-delete">
            </el-button>
          </div>
        </el-form-item>
        <el-form-item v-if="dialogMode !== 'view'">
          <el-button @click="addCell" size="medium" icon="el-icon-plus" style="border-style: dashed; width: 100%">
            单元格
          </el-button>
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="handleCancelCreate" size="medium">取 消</el-button>
        <el-button type="primary" @click="handleConfirmCreate" size="medium">确 定</el-button>
      </div>
    </el-dialog>
    <el-dialog :title="jsonViewTitle" :visible.sync="jsonViewVisible" :append-to-body="true">
      <json-viewer :value="json"></json-viewer>
    </el-dialog>
    <el-drawer :title="mode === 'frontend' ? '前端解析' : '后端解析'" :visible.sync="drawerVisible" direction="rtl">
      <div style="margin: 20px; display: flex; flex-direction: row; align-items: center;">
        <div style="width: 100px;">行键</div>
        <el-select style="margin-left: auto;" :value="rowKeyDataType" @change="handleRowKeyDataTypeSelectChange($event)"
          size="mini" placeholder="数据类型">
          <el-option v-for="item in dataTypes" :key="item" :label="item" :value="item">
          </el-option>
        </el-select>
      </div>
      <el-tree style="margin-left: 10px; margin-right: 10px;" :data="treeData" node-key="key"
        :default-expand-all="false" :expand-on-click-node="true" :accordion="true">
        <template v-slot="{ node }">
          <div style="flex:1; display: flex; flex-direction: row; align-items: center;">
            <div style="width: 100px;">{{ node.data.label }}</div>
            <el-select style="margin-left: auto; margin-right: 10px;" :value="node.data.value"
              @change="handleDataTypeSelectChange($event, node)" size="mini" placeholder="数据类型">
              <el-option v-for="item in dataTypes" :key="item" :label="item" :value="item">
              </el-option>
            </el-select>
          </div>
        </template>
      </el-tree>
    </el-drawer>
  </div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import api from '@/api'
export default {
  props: {
    connectionId: {
      type: String,
      default: ''
    },
    tableName: {
      type: String,
      default: ''
    },
    families: {
      type: Array,
      default: () => []
    }
  },
  components: {},
  data() {
    return {
      loading: false,
      multipleSelection: [],
      dataTypes: [],
      tableData: [],
      jsonViewVisible: false,
      jsonViewTitle: '',
      json: '',
      columns: [],
      rowKeyDataType: null,
      drawerVisible: false,
      treeData: [],
      dialogMode: 'view',
      dialogVisible: false,
      row: {
        rowKey: '',
        rowKeyDataType: null,
        cells: []
      }
    }
  },
  computed: {
    ...mapGetters({
      dataTypeMap: 'profile/getDataTypeMap',
      mode: 'profile/getMode'
    })
  },
  watch: {
    async drawerVisible(newVal) {
      if (!newVal) {
        await this.refresh()
      }
    },
    async mode() {
      const resp = await api.dataType.getDataTypes(this.mode)
      if (resp.ok) {
        this.dataTypes = Object.freeze(resp.data ?? [])
      } else {
        this.$message({ message: resp.message, type: 'error', duration: 1500 })
      }
    }
  },
  methods: {
    async refresh() {
      this.loading = true
      const resp = await api.row.listRow(
        this.mode,
        this.connectionId,
        this.tableName,
        null,
        this.rowKeyDataType,
        this.getValueDataTypeMap()
      )
      if (resp.ok) {
        const data = resp.data
        const columnMap = new Map()
        for (const row of data) {
          const cells = row.cells
          for (const cell of cells) {
            const family = cell.family
            const qualifier = cell.qualifier
            const value = cell.value
            row[`${family}:${qualifier}`] = value
            if (columnMap.has(family)) {
              columnMap.get(family).add(qualifier)
            } else {
              columnMap.set(family, new Set([qualifier]))
            }
          }
        }
        const treeData = []
        const columns = []
        for (const [family, qualifiers] of columnMap.entries()) {
          const list = [...qualifiers]
          list.sort()
          columns.push({ family, qualifiers: list })
          treeData.push({
            key: family,
            label: family,
            family: family,
            qualifier: null,
            value: '',
            children: list.map(qualifier => ({
              key: `${family}:${qualifier}`,
              label: qualifier,
              family: family,
              qualifier: qualifier,
              value: this.dataTypeMap?.[this.tableName]?.[`${family}:${qualifier}`] ?? 'Hex'
            }))
          })
        }
        this.treeData = treeData
        this.columns = Object.freeze(columns)
        this.tableData = Object.freeze(data)
      } else {
        this.$message({ message: resp.message, type: 'error', duration: 1500 })
      }
      this.loading = false
    },
    create() {
      this.dialogMode = 'edit'
      this.row = {
        rowKey: '',
        rowKeyDataType: this.rowKeyDataType,
        cells: []
      }
      this.dialogVisible = true
    },
    addCell() {
      this.row.cells.push({
        key: Date.now(),
        family: this.families?.[0]?.name ?? '',
        qualifier: '',
        valueDataType: 'UTF-8',
        value: ''
      })
    },
    removeCell(key) {
      const cells = JSON.parse(JSON.stringify(this.row.cells ?? []))
      this.row.cells = cells.filter(cell => cell.key !== key)
    },
    handleCancelCreate() {
      this.dialogVisible = false
    },
    async handleConfirmCreate() {
      const resp = await api.row.createRow(
        this.mode,
        this.connectionId,
        this.tableName,
        this.row.rowKey,
        this.row.rowKeyDataType,
        this.row.cells.map(item => ({
          family: item.family,
          qualifier: item.qualifier,
          valueDataType: item.valueDataType,
          value: item.value
        }))
      )
      if (resp.ok) {
        this.$message({ message: '更新成功', type: 'info', duration: 1000 })
        this.dialogVisible = false
        await this.refresh()
      } else {
        this.$message({ message: resp.message, type: 'error', duration: 1500 })
      }
    },
    show(row) {
      this.dialogMode = 'view'
      const valueDataTypeMap = this.getValueDataTypeMap()
      this.row = {
        rowKey: row.rowKey,
        rowKeyDataType: this.rowKeyDataType,
        cells: row.cells.map(
          (it, index) => Object.assign(
            it,
            {
              key: index,
              valueDataType: valueDataTypeMap[`${it.family}:${it.qualifier}`]
            }
          )
        )
      }
      this.dialogVisible = true
    },
    async deleteRow(row) {
      const resp = await api.row.deleteRow(
        this.mode,
        this.connectionId,
        this.tableName,
        [row.rowKey],
        this.rowKeyDataType
      )
      if (resp.ok) {
        this.$message({ message: '删除成功', type: 'info', duration: 1000 })
      } else {
        this.$message({ message: resp.message, type: 'error', duration: 1500 })
      }
      await this.refresh()
    },
    async deleteData() {
      const resp = await api.row.deleteRow(
        this.mode,
        this.connectionId,
        this.tableName,
        this.multipleSelection.map(item => item.rowKey),
        this.rowKeyDataType
      )
      if (resp.ok) {
        this.$message({ message: '删除成功', type: 'info', duration: 1000 })
      } else {
        this.$message({ message: resp.message, type: 'error', duration: 1500 })
      }
      await this.refresh()
    },
    handleRowKeyDataTypeSelectChange(newValue) {
      this.rowKeyDataType = newValue
      this.storeRowKeyDataType({ tableName: this.tableName, value: newValue })
    },
    handleDataTypeSelectChange(newValue, node) {
      if (!node.data.qualifier) {
        for (const item of node.childNodes) {
          item.data.value = newValue
          this.storeValueDataType({
            tableName: this.tableName,
            family: item.data.family,
            qualifier: item.data.qualifier,
            value: newValue
          })
        }
      } else {
        node.data.value = newValue
        this.storeValueDataType({
          tableName: this.tableName,
          family: node.data.family,
          qualifier: node.data.qualifier,
          value: newValue
        })
      }
    },
    getValueDataTypeMap() {
      if (this.treeData && this.treeData.length > 0) {
        const map = {}
        for (const treeNode of this.treeData) {
          for (const item of treeNode.children) {
            map[`${item.family}:${item.qualifier}`] = item.value
          }
        }
        return map
      } else {
        return this.dataTypeMap?.[this.tableName] ?? {}
      }
    },
    openJsonView(title, text) {
      this.jsonViewTitle = title
      let json = text
      try {
        json = JSON.parse(text)
      } catch (e) {
        console.error(e)
      }
      this.json = json
      this.jsonViewVisible = true
    },
    ...mapActions({
      storeRowKeyDataType: 'profile/setRowKeyDataType',
      storeValueDataType: 'profile/setValueDataType'
    })
  },
  beforeCreate() { },
  async created() {
    const resp = await api.dataType.getDataTypes(this.mode)
    if (resp.ok) {
      this.dataTypes = Object.freeze(resp.data ?? [])
    } else {
      this.$message({ message: resp.message, type: 'error', duration: 1500 })
    }
    this.rowKeyDataType = this.dataTypeMap?.[this.tableName]?.['rowKey'] ?? 'Hex'
    await this.refresh()
  },
  beforeDestroy() { },
  destroyed() { }
}
</script>
<style lang="scss" scoped>
::v-deep {
  .el-tree-node__content {
    height: 48px;
  }

  .el-table--border .el-table__cell:first-child .cell {
    padding-left: 15px;
    padding-right: 15px;
  }

  .el-table .cell {

    .value {
      display: inline-flex;
      width: 100%;
      text-align: center;
      justify-content: center;
    }
  }
}
</style>